package com.chen.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.chen.dto.UserDto;
import com.chen.fegin.UserFegin;
import com.chen.model.Records;
import com.chen.service.RecordsService;
import com.google.common.collect.Lists;
import lombok.Builder;
import lombok.Data;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.lang.annotation.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: chen
 * @Date: 2021/5/12 10:33 AM
 * @Version 1.0
 */
@Service
public class RecordsServiceImpl<T extends Records> implements RecordsService<T> {

    private static final String SET = "set";
    private static final String GET = "get";

    @Resource
    private UserFegin userFegin;

    public List<Long> feginToIds(Page<T> page,
                                 Long userId,
                                 String userName,
                                 String mobile,
                                 Map<Long, UserDto> user
    ) {
        //------- 通过参数远程调用获取的userid
        //远程调用会员系统之后，把查询到的id汇集到这个集合
        List<Long> searchIds = new ArrayList<>();
        //如果用户名，手机号，用户id不等于null，远程调用会员系统
        if (StringUtils.isNotBlank(userName) ||
                StringUtils.isNotBlank(mobile) ||
                userId != null) {
            ArrayList<Long> ids = Lists.newArrayList();
            if (userId != null) {
                ids.add(userId);
            }
            user.putAll(userFegin.getUser(ids.size() == 0 ? null : ids, userName, mobile, page.getCurrent(), page.getSize()));
            Set<Map.Entry<Long, UserDto>> entries = user.entrySet();
            for (Map.Entry<Long, UserDto> map : entries) {
                searchIds.add(map.getKey());
            }
            if (CollectionUtils.isEmpty(searchIds)) {
                return Collections.emptyList();
            }
        }
        return searchIds;
    }


    @Override
    public Page<T> findData(Page<T> page,
                            BaseMapper<T> baseMapper,
                            RecordsServiceImpl.SearchRecords searchRecords) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException, NoSuchFieldException {

        Map<Long, UserDto> user = new HashMap<>();
        List<Long> searchIds = feginToIds(page, searchRecords.getUserId(), searchRecords.getUserName(), searchRecords.getMobile(), user);
        //查询数据库【充值表】
        QueryWrapper<T> objectQueryWrapper = new QueryWrapper<>();
        objectQueryWrapper.in(!CollectionUtils.isEmpty(searchIds), "user_id", searchIds);

        //构造查询条件
        Class<? extends SearchRecords> bClass = searchRecords.getClass();
        Field[] declaredFields = bClass.getDeclaredFields();
        for (Field field : declaredFields) {
            RecordsAnn declaredAnnotation = field.getAnnotation(RecordsAnn.class);
            if (declaredAnnotation != null) {
                if (!declaredAnnotation.isColumn()) {
                    continue;
                }
            }
            String name = field.getName();
            name = name.replaceFirst(name.substring(0, 1), name.substring(0, 1).toUpperCase());
            Method method = bClass.getMethod(GET + name);
            Object invoke = method.invoke(searchRecords);
            String column = getColumn(field.getName());
            objectQueryWrapper.eq(invoke != null, column, invoke);
        }

//        objectQueryWrapper.eq(searchRecords.getStatus() != null, "status", searchRecords.getStatus());
//        objectQueryWrapper.eq(searchRecords.getAccountId() != null, "account_id", searchRecords.getAccountId());
//        objectQueryWrapper.eq(searchRecords.getCoinId() != null, "coin_id", searchRecords.getCoinId());

        objectQueryWrapper.orderByDesc("created");

        //解析区间参数
        Map<SearchRecords.BetweenDataEnum, Map<String, SearchRecords.LimitRecords>> betweenData = searchRecords.getBetweenData();
        if (betweenData != null) {
            SearchRecords.BetweenDataEnum[] values = SearchRecords.BetweenDataEnum.values();
            for (SearchRecords.BetweenDataEnum enums : values) {
                Map<String, SearchRecords.LimitRecords> amount = betweenData.get(enums);
                if (amount != null) {
                    setSearchQueryWrapper(objectQueryWrapper, amount);
                }
            }
        }
        Page<T> rechargePage = baseMapper.selectPage(page, objectQueryWrapper);
        if (CollectionUtils.isEmpty(rechargePage.getRecords())) {
            return rechargePage;
        }
        //如果searchIds 不等null 说明之前没有发送远程调用，需要远程调用来获取数据
        if (CollectionUtils.isEmpty(searchIds)) {
            List<T> records = rechargePage.getRecords();

            ArrayList<Long> longs = records.stream().map(t -> {
                assert t != null;
                Class<?> aClass = t.getClass();
                Field declaredField = null;
                try {
                    declaredField = aClass.getDeclaredField("userId");
                } catch (NoSuchFieldException e) {
                    e.printStackTrace();
                }
                assert declaredField != null;
                String name = declaredField.getName();
                name = name.replaceFirst(name.substring(0, 1), name.substring(0, 1).toUpperCase());
                Method m = null;
                try {
                    m = aClass.getMethod(GET + name);
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                }
                try {
                    assert m != null;
                    return (Long) m.invoke(t);
                } catch (IllegalAccessException | InvocationTargetException e) {
                    e.printStackTrace();
                }
                return null;
            }).collect(Collectors.toCollection(ArrayList::new));
            user = userFegin.getUser(longs.size() == 0 ? null : longs, null, null, null, null);
            buildData(user, records);
            return rechargePage;
        } else {
            List<T> records = rechargePage.getRecords();
            buildData(user, records);
            return rechargePage;
        }
    }


    /**
     * 将 userName  转为  user_name  用作查询的列
     * @param name
     * @return
     */
    private String getColumn(String name) {
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < name.length(); i++) {
            char ch = name.charAt(i);
            if (Character.isUpperCase(ch)) {
                if(i != 0){
                    stringBuilder.append("_");
                }
                stringBuilder.append(Character.toLowerCase(ch));
                continue;
            }
            stringBuilder.append(ch);
        }
        return stringBuilder.toString();


    }

    //构造区间查询参数
    private void setSearchQueryWrapper(QueryWrapper<T> objectQueryWrapper, Map<String, SearchRecords.LimitRecords> amount) {
        if (amount != null) {
            Set<Map.Entry<String, SearchRecords.LimitRecords>> entries = amount.entrySet();
            for (Map.Entry<String, SearchRecords.LimitRecords> map : entries) {
                SearchRecords.LimitRecords value = map.getValue();
                objectQueryWrapper.ge(StringUtils.isNotBlank(value.getMin()), map.getKey(), value.getMin());
                objectQueryWrapper.le(StringUtils.isNotBlank(value.getMax()), map.getKey(), value.getMax());
            }
        }
    }

    public void buildData(Map<Long, UserDto> user, List<T> records) throws NoSuchFieldException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        for (T t : records) {
            //反射获取泛形的对象
            Class<?> aClass = t.getClass();
            //获取的userId的属性
            Field declaredField = aClass.getDeclaredField("userId");
            //获取属性的名字
            String name = declaredField.getName();
            //把首字母大写
            name = name.replaceFirst(name.substring(0, 1), name.substring(0, 1).toUpperCase());
            Method m = aClass.getMethod(GET + name);
            //执行get方法
            Long id = (Long) m.invoke(t);
            UserDto userDto = user.get(id);

            Field declaredFieldRealName = aClass.getDeclaredField("realName");
            String nameRealName = declaredFieldRealName.getName();
            nameRealName = nameRealName.replaceFirst(nameRealName.substring(0, 1), nameRealName.substring(0, 1).toUpperCase());
            Method mRealName = aClass.getMethod(SET + nameRealName, String.class);
            Field declaredFieldMobile = aClass.getDeclaredField("mobile");
            String nameMobile = declaredFieldMobile.getName();
            nameMobile = nameMobile.replaceFirst(nameMobile.substring(0, 1), nameMobile.substring(0, 1).toUpperCase());
            Method mMobile = aClass.getMethod(SET + nameMobile, String.class);
            Field declaredFieldUserName = aClass.getDeclaredField("username");
            String nameUserName = declaredFieldUserName.getName();
            nameUserName = nameUserName.replaceFirst(nameUserName.substring(0, 1), nameUserName.substring(0, 1).toUpperCase());
            Method mUserName = aClass.getMethod(SET + nameUserName, String.class);
            if (userDto != null) {
                mRealName.invoke(t, userDto.getRealName());
                mMobile.invoke(t, userDto.getMobile());
                mUserName.invoke(t, userDto.getUsername());
            } else {
                mRealName.invoke(t, "数据为空");
                mMobile.invoke(t, "数据为空");
                mUserName.invoke(t, "数据为空");
            }
        }
    }

    //用来判断不需要的查询条件
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface RecordsAnn {
        boolean isColumn() default true;
    }

    @Data
    public static class SearchRecords {
        private Long userId;
        @RecordsAnn(isColumn = false)
        private String userName;
        @RecordsAnn(isColumn = false)
        private String mobile;
        private Byte status;
        private Long accountId;
        private Long coinId;

        @RecordsAnn(isColumn = false)
        private Map<BetweenDataEnum, Map<String, LimitRecords>> betweenData;

        //区分不同区间参数中的枚举
        @Getter
        public enum BetweenDataEnum {
            AMOUNT, TIME
        }

        //区间参数中的值
        @Data
        @Builder
        static class LimitRecords {

            private String min;

            private String max;

        }
    }

}
